package com.sherllinhe.generator.gen;

import com.sherllinhe.generator.util.DbUtil;
import com.sherllinhe.generator.util.Field;
import com.sherllinhe.generator.util.FreemarkerUtil;
import freemarker.template.TemplateException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 功能：生成数据库表对应的service层和controller层
 * 作者：Sherllin He
 * 日期：2025/5/9 15:19
 */

public class ServerGenerator {
    static boolean readOnly = false;

    static String vuePath = "generator/src/main/java/com/sherllinhe/generator/vue/";
    static String serverPath = "[module]/src/main/java/com/sherllinhe/[module]/";
    static String pomPath = "generator/pom.xml";

    public static void main(String[] args) throws Exception {
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ 读取pom文件------------------------");

        //获取mybatis-generator配置文件路径
        String generatorPath = getGeneratorPath();
        System.out.println("mybatis官方生成器xml文件路径："+generatorPath);

        //获取模块名
        String moduleName = generatorPath.replace("src/main/resources/generator-config-", "").replace(".xml", "");
        System.out.println("模块名：" + moduleName);

        serverPath = serverPath.replace("[module]",moduleName);

        new File(serverPath).mkdirs();

        //读取mybatis-generator配置文件
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ 读取mybatis-generator配置文件-----------------------");
        Document document = new SAXReader().read("generator/" + generatorPath);
        Node table = document.selectSingleNode("//table");
        System.out.println("获取table标签中信息...");
        Node tableName = table.selectSingleNode("@tableName");
        Node domainObjectName = table.selectSingleNode("@domainObjectName");
        System.out.println("tableName属性值：" + tableName.getText());
        System.out.println("domainObjectName属性值：" + domainObjectName.getText());

        //为DBUtil设置数据库连接信息
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ 为DBUtil设置数据库连接信息------------------------");
        Node connectionURL = document.selectSingleNode("//@connectionURL");
        Node userId = document.selectSingleNode("//@userId");
        Node password = document.selectSingleNode("//@password");
        System.out.println("connectionURL属性值：" + connectionURL.getText());
        System.out.println("userId属性值：" + userId.getText());
        System.out.println("password属性值：" + password.getText());
        DbUtil.url = connectionURL.getText();
        DbUtil.user = userId.getText();
        DbUtil.password = password.getText();

        //数据库表信息
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ 数据库表信息------------------------");
        String tableNameCn = DbUtil.getTableComment(tableName.getText());
        List<Field> fieldList = DbUtil.getColumnByTableName(tableName.getText());
        Set<String> typeSet = getJavaTypes(fieldList);

        //组装参数
        String Domain = domainObjectName.getText();
        String domain = Domain.substring(0, 1).toLowerCase() + Domain.substring(1);
        String do_main = tableName.getText().replaceAll("_","-");
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ 组装参数------------------------");
        Map<String,Object> param = new HashMap<String,Object>();
        param.put("module",moduleName);
        param.put("Domain", Domain);
        param.put("domain",domain);
        param.put("do_main",do_main);
        param.put("tableNameCn",tableNameCn);
        param.put("fieldList",fieldList);
        param.put("typeSet",typeSet);
        param.put("readOnly",readOnly);
        System.out.println(param);

        //代码生成
        System.out.println("----( ๑ˊ•̥▵•)੭₎₎₎ "+domain+"表对应代码生成如下------------------------");
        String fileName = "";
//        生成服务层和控制层
        fileName = generateCode(Domain, param,"service","service");
        System.out.println("服务层生成完毕，路径为："+fileName);
        fileName = generateCode(Domain, param,"controller","controller");
        System.out.println("控制层生成完毕，路径为："+fileName);
//        生成实体类
        fileName = generateCode(Domain, param,"req","saveReq");
        System.out.println("saveReq实体类生成完毕，路径为："+fileName);
        fileName = generateCode(Domain, param,"req","queryReq");
        System.out.println("queryReq实体类生成完毕，路径为："+fileName);
        fileName = generateCode(Domain, param,"resp","queryResp");
        System.out.println("queryResp实体类生成完毕，路径为："+fileName);
        //生成前端页面
        fileName = generateVue(Domain, param);
        System.out.println("vue页面生成完毕，路径为："+fileName);
    }

    //生成服务端代码
    private static String generateCode(String Domain, Map<String, Object> param,String packageName,String target) throws IOException, TemplateException {
        FreemarkerUtil.initConfig(target+".ftl");
        String Target = target.substring(0, 1).toUpperCase() + target.substring(1);
        String toPath = serverPath+ packageName+"/";
        new File(toPath).mkdirs();
        String fileName = toPath+Domain +Target+".java";
        FreemarkerUtil.generator(fileName, param);
        return fileName;
    }
    //生成前端代码
    private static String generateVue(String Domain, Map<String, Object> param) throws IOException, TemplateException {
        FreemarkerUtil.initConfig("vue.ftl");
        new File(vuePath).mkdirs();
        String fileName = vuePath+Domain+"View.vue";
        FreemarkerUtil.generator(fileName, param);
        return fileName;
    }

    //获取mybatis-generator配置文件路径
    private static String getGeneratorPath() throws DocumentException {
        SAXReader saxReader = new SAXReader();
        Map<String, String> map = new HashMap<String,String>();
        map.put("pom", "http://maven.apache.org/POM/4.0.0");
        saxReader.getDocumentFactory().setXPathNamespaceURIs(map);
        Document document = saxReader.read(pomPath);
        Node node = document.selectSingleNode("//pom:configurationFile");
        return node.getText();
    }

    //获取所有Java类型，使用Set去重
    private static Set<String> getJavaTypes(List<Field> fieldList) {
        Set<String> set = new HashSet<String>();
        for (Field field : fieldList) {
            Field f = fieldList.get(fieldList.indexOf(field));
            set.add(f.getJavaType());
        }
        return set;
    }
}
